# API网关主应用

import os
import httpx
from fastapi import FastAPI, Request, Response, HTTPException, Depends, Header
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from config import settings

# 创建FastAPI应用
app = FastAPI(
    title=settings.PROJECT_NAME,
    description=settings.PROJECT_DESCRIPTION,
    version=settings.VERSION,
    docs_url="/docs",
    redoc_url="/redoc",
)

# 配置CORS
cors_origins = settings.cors_origins_list
if cors_origins and cors_origins[0] == "*":
    # 如果是通配符，直接使用 "*"
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
else:
    # 否则使用配置的具体域名
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[str(origin) for origin in cors_origins],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

# 服务状态
service_status = {
    "audio_to_text": {"status": "unknown", "last_check": None},
    "video_to_speech": {"status": "unknown", "last_check": None},
}

# 简单的API密钥验证依赖
async def verify_api_key(api_key: str = Header(None, alias=settings.API_KEY_HEADER)):
    """
    验证API密钥
    """
    if settings.API_KEY and settings.API_KEY != "":
        if not api_key:
            raise HTTPException(
                status_code=401,
                detail="缺少API密钥"
            )
        if api_key != settings.API_KEY:
            raise HTTPException(
                status_code=403,
                detail="API密钥无效"
            )
    return True

@app.get("/", tags=["健康检查"])
async def health_check():
    """
    网关健康检查接口
    """
    return {
        "status": "healthy",
        "service": "api-gateway",
        "services": service_status
    }

@app.get("/services/status", tags=["服务状态"])
async def get_services_status(_: bool = Depends(verify_api_key)):
    """
    获取所有服务的状态
    """
    # 更新服务状态
    await check_services_health()
    
    return {
        "services": service_status
    }

async def check_services_health():
    """
    检查所有服务的健康状态
    """
    from datetime import datetime
    
    async with httpx.AsyncClient(timeout=5.0) as client:
        # 检查音频转文字服务
        try:
            response = await client.get(f"{settings.AUDIO_TO_TEXT_SERVICE_URL}/")
            if response.status_code == 200:
                service_status["audio_to_text"] = {
                    "status": "healthy",
                    "last_check": datetime.now().isoformat()
                }
            else:
                service_status["audio_to_text"] = {
                    "status": "unhealthy",
                    "last_check": datetime.now().isoformat()
                }
        except Exception:
            service_status["audio_to_text"] = {
                "status": "unreachable",
                "last_check": datetime.now().isoformat()
            }
        
        # 检查视频转语音服务
        try:
            response = await client.get(f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/")
            if response.status_code == 200:
                service_status["video_to_speech"] = {
                    "status": "healthy",
                    "last_check": datetime.now().isoformat()
                }
            else:
                service_status["video_to_speech"] = {
                    "status": "unhealthy",
                    "last_check": datetime.now().isoformat()
                }
        except Exception:
            service_status["video_to_speech"] = {
                "status": "unreachable",
                "last_check": datetime.now().isoformat()
            }

# 直接文件上传接口
from fastapi import UploadFile, File, Form
from typing import Optional

@app.post("/upload/audio-to-text", tags=["文件上传"])
async def upload_audio_to_text(
    file: UploadFile = File(..., description="音频文件"),
    language: Optional[str] = Form(None, description="语言代码，如：zh-CN, en-US"),
    _: bool = Depends(verify_api_key)
):
    """
    上传音频文件并转换为文字
    
    支持的音频格式：wav, mp3, m4a, flac, ogg
    """
    # 创建新的请求对象来代理到音频转文字服务
    import io
    from fastapi import Form
    
    # 准备表单数据
    files = {"file": (file.filename, file.file, file.content_type)}
    data = {}
    if language:
        data["language"] = language
    
    try:
        async with httpx.AsyncClient(timeout=120.0) as client:
            response = await client.post(
                f"{settings.AUDIO_TO_TEXT_SERVICE_URL}/api/v1/audio-to-text",
                files=files,
                data=data,
                headers={settings.API_KEY_HEADER: settings.API_KEY} if settings.API_KEY else {}
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                return JSONResponse(
                    status_code=response.status_code,
                    content=response.json() if response.headers.get("content-type", "").startswith("application/json") else {"detail": response.text}
                )
    except httpx.RequestError as e:
        return JSONResponse(
            status_code=503,
            content={"detail": f"音频转文字服务不可用: {str(e)}"},
        )

@app.post("/upload/video-to-speech", tags=["文件上传"])
async def upload_video_to_speech(
    file: UploadFile = File(..., description="视频文件"),
    language: Optional[str] = Form(None, description="语言代码，如：zh-CN, en-US"),
    speed: Optional[float] = Form(1.0, description="语音速度倍数，默认1.0"),
    _: bool = Depends(verify_api_key)
):
    """
    上传视频文件并转换为语音
    
    支持的视频格式：mp4, avi, mov, mkv, flv
    """
    # 准备表单数据
    files = {"file": (file.filename, file.file, file.content_type)}
    data = {}
    if language:
        data["language"] = language
    if speed:
        data["speed"] = str(speed)
    
    try:
        async with httpx.AsyncClient(timeout=300.0) as client:  # 视频处理需要更长时间
            response = await client.post(
                f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/api/v1/video-to-speech",
                files=files,
                data=data,
                headers={settings.API_KEY_HEADER: settings.API_KEY} if settings.API_KEY else {}
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                return JSONResponse(
                    status_code=response.status_code,
                    content=response.json() if response.headers.get("content-type", "").startswith("application/json") else {"detail": response.text}
                )
    except httpx.RequestError as e:
        return JSONResponse(
            status_code=503,
            content={"detail": f"视频转语音服务不可用: {str(e)}"},
        )

@app.post("/upload/extract-audio", tags=["文件上传"])
async def upload_extract_audio(
    file: UploadFile = File(..., description="视频文件"),
    _: bool = Depends(verify_api_key)
):
    """
    从上传的视频文件中提取音频
    
    支持的视频格式：mp4, avi, mov, mkv, flv
    """
    # 准备表单数据
    files = {"file": (file.filename, file.file, file.content_type)}
    
    try:
        async with httpx.AsyncClient(timeout=180.0) as client:
            response = await client.post(
                f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/api/v1/extract-audio",
                files=files,
                headers={settings.API_KEY_HEADER: settings.API_KEY} if settings.API_KEY else {}
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                return JSONResponse(
                    status_code=response.status_code,
                    content=response.json() if response.headers.get("content-type", "").startswith("application/json") else {"detail": response.text}
                )
    except httpx.RequestError as e:
        return JSONResponse(
            status_code=503,
            content={"detail": f"视频转语音服务不可用: {str(e)}"},
        )

# 获取支持的格式信息
@app.get("/supported-formats", tags=["系统信息"])
async def get_all_supported_formats():
    """
    获取所有服务支持的格式信息
    """
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            # 获取音频格式
            audio_response = await client.get(f"{settings.AUDIO_TO_TEXT_SERVICE_URL}/api/v1/supported-formats")
            audio_formats = audio_response.json() if audio_response.status_code == 200 else {"formats": []}
            
            # 获取视频格式
            video_response = await client.get(f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/api/v1/supported-formats")
            video_formats = video_response.json() if video_response.status_code == 200 else {"formats": []}
            
            # 获取语言支持
            audio_lang_response = await client.get(f"{settings.AUDIO_TO_TEXT_SERVICE_URL}/api/v1/supported-languages")
            audio_languages = audio_lang_response.json() if audio_lang_response.status_code == 200 else {"languages": [], "default": "zh-CN"}
            
            return {
                "audio": {
                    "formats": audio_formats.get("formats", []),
                    "languages": audio_languages.get("languages", []),
                    "default_language": audio_languages.get("default", "zh-CN")
                },
                "video": {
                    "formats": video_formats.get("formats", []),
                    "languages": audio_languages.get("languages", []),  # 视频转语音使用相同的语言支持
                    "default_language": audio_languages.get("default", "zh-CN")
                }
            }
    except Exception as e:
        return JSONResponse(
            status_code=503,
            content={"detail": f"无法获取格式信息: {str(e)}"},
        )

@app.post("/audio-to-text", tags=["音频转文字"])
async def audio_to_text_proxy(request: Request):
    """
    音频转文字服务代理
    """
    return await proxy_request(
        request, 
        f"{settings.AUDIO_TO_TEXT_SERVICE_URL}/api/v1/audio-to-text"
    )

@app.post("/video-to-speech", tags=["视频转语音"])
async def video_to_speech_proxy(request: Request):
    """
    视频转语音服务代理
    """
    return await proxy_request(
        request, 
        f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/api/v1/video-to-speech"
    )

@app.post("/extract-audio", tags=["音频提取"])
async def extract_audio_proxy(request: Request):
    """
    音频提取服务代理
    """
    return await proxy_request(
        request, 
        f"{settings.VIDEO_TO_SPEECH_SERVICE_URL}/api/v1/extract-audio"
    )

async def proxy_request(request: Request, target_url: str):
    """
    代理请求到目标服务
    """
    # 获取请求方法和头信息
    method = request.method
    headers = dict(request.headers)
    
    # 移除host头，避免冲突
    headers.pop("host", None)
    
    # 获取请求体
    body = await request.body()
    
    # 获取查询参数
    params = dict(request.query_params)
    
    try:
        # 创建HTTP客户端
        async with httpx.AsyncClient(timeout=60.0) as client:
            # 发送请求到目标服务
            response = await client.request(
                method=method,
                url=target_url,
                headers=headers,
                params=params,
                content=body,
            )
            
            # 构建响应
            return Response(
                content=response.content,
                status_code=response.status_code,
                headers=dict(response.headers),
            )
    except httpx.RequestError as e:
        # 处理请求错误
        return JSONResponse(
            status_code=503,
            content={"detail": f"服务不可用: {str(e)}"},
        )

# 健康检查端点
@app.get("/health", tags=["系统信息"])
async def health_check():
    """
    API网关健康检查
    """
    return {"status": "healthy", "service": "api-gateway"}

# 格式查询端点（兼容性）
@app.get("/formats", tags=["系统信息"])
async def get_formats():
    """
    获取支持的格式信息（兼容性端点）
    """
    return await get_all_supported_formats()

# 启动时检查服务健康状态
@app.on_event("startup")
async def startup_event():
    await check_services_health()

if __name__ == "__main__":
    import uvicorn
    port = int(os.getenv("PORT", 8002))
    uvicorn.run("app:app", host="0.0.0.0", port=port, reload=True)